package com.zhentao.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhentao.dto.ParamCategoryDTO;
import com.zhentao.dto.ParamCategoryQueryDTO;
import com.zhentao.mapper.ParamCategoryMapper;
import com.zhentao.mapper.ParamDefinitionMapper;
import com.zhentao.pojo.ParamCategory;
import com.zhentao.pojo.ParamDefinition;
import com.zhentao.service.ParamCategoryService;
import com.zhentao.vo.ParamCategoryTreeVO;
import com.zhentao.vo.ParamCategoryVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
* @author hp
* @description 针对表【param_category(参数分类表：管理参数的层级分类结构)】的数据库操作Service实现
* @createDate 2025-08-28 08:36:25
*/
@Service
public class ParamCategoryServiceImpl extends ServiceImpl<ParamCategoryMapper, ParamCategory>
    implements ParamCategoryService{

    @Autowired
    private ParamDefinitionMapper paramDefinitionMapper;

    @Override
    public List<ParamCategoryTreeVO> getCategoryTree() {
        // 获取所有启用的分类
        List<ParamCategory> allCategories = getAllEnabledCategories();
        
        // 构建树形结构
        return buildCategoryTree(allCategories, null);
    }

    @Override
    public List<ParamCategoryTreeVO> getCategoryTreeByParent(Long parentId) {
        // 获取所有启用的分类
        List<ParamCategory> allCategories = getAllEnabledCategories();
        
        // 构建指定父分类下的树形结构
        return buildCategoryTree(allCategories, parentId);
    }

    @Override
    public Page<ParamCategoryVO> queryCategories(ParamCategoryQueryDTO queryDTO) {
        // 构建查询条件
        LambdaQueryWrapper<ParamCategory> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.hasText(queryDTO.getCategoryCode()), ParamCategory::getCategoryCode, queryDTO.getCategoryCode())
                   .like(StringUtils.hasText(queryDTO.getCategoryName()), ParamCategory::getCategoryName, queryDTO.getCategoryName())
                   .eq(queryDTO.getParentId() != null, ParamCategory::getParentId, queryDTO.getParentId())
                   .eq(queryDTO.getStatus() != null, ParamCategory::getStatus, queryDTO.getStatus());
        
        // 处理顶级分类查询
        if (Boolean.TRUE.equals(queryDTO.getTopLevel())) {
            queryWrapper.isNull(ParamCategory::getParentId);
        }
        
        // 排序
        queryWrapper.orderByAsc(ParamCategory::getSortOrder)
                   .orderByDesc(ParamCategory::getCreateTime);

        // 分页查询
        Page<ParamCategory> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize());
        Page<ParamCategory> resultPage = this.page(page, queryWrapper);

        // 转换为VO
        Page<ParamCategoryVO> voPage = new Page<>();
        BeanUtils.copyProperties(resultPage, voPage);
        
        List<ParamCategoryVO> voList = resultPage.getRecords().stream()
                .map(entity -> convertToVO(entity, queryDTO.getIncludeChildCount()))
                .collect(Collectors.toList());
        voPage.setRecords(voList);

        return voPage;
    }

    @Override
    public ParamCategoryVO getCategoryDetail(Long id) {
        ParamCategory category = this.getById(id);
        if (category == null) {
            return null;
        }
        return convertToVO(category, true);
    }

    @Override
    public boolean createCategory(ParamCategoryDTO dto) {
        // 检查分类编码是否已存在
        if (!isCategoryCodeAvailable(dto.getCategoryCode(), null)) {
            throw new RuntimeException("分类编码已存在：" + dto.getCategoryCode());
        }
        
        // 如果有父分类，检查父分类是否存在
        if (dto.getParentId() != null) {
            ParamCategory parentCategory = this.getById(dto.getParentId());
            if (parentCategory == null) {
                throw new RuntimeException("父分类不存在");
            }
            if (parentCategory.getStatus() == 0) {
                throw new RuntimeException("父分类已禁用，无法在其下创建子分类");
            }
        }
        
        ParamCategory category = new ParamCategory();
        BeanUtils.copyProperties(dto, category);
        category.setCreateTime(new Date());
        
        return this.save(category);
    }

    @Override
    public boolean updateCategory(Long id, ParamCategoryDTO dto) {
        ParamCategory existCategory = this.getById(id);
        if (existCategory == null) {
            throw new RuntimeException("分类不存在");
        }
        
        // 检查分类编码是否已存在（排除当前记录）
        if (!isCategoryCodeAvailable(dto.getCategoryCode(), id)) {
            throw new RuntimeException("分类编码已存在：" + dto.getCategoryCode());
        }
        
        // 检查是否试图将分类设置为自己的子分类（防止循环引用）
        if (dto.getParentId() != null && dto.getParentId().equals(id)) {
            throw new RuntimeException("不能将分类设置为自己的子分类");
        }
        
        // 检查是否试图将分类设置为自己后代的子分类
        if (dto.getParentId() != null && isDescendant(id, dto.getParentId())) {
            throw new RuntimeException("不能将分类设置为自己后代的子分类");
        }
        
        BeanUtils.copyProperties(dto, existCategory);
        existCategory.setUpdateTime(new Date());
        
        return this.updateById(existCategory);
    }

    @Override
    public boolean deleteCategory(Long id) {
        ParamCategory category = this.getById(id);
        if (category == null) {
            throw new RuntimeException("分类不存在");
        }
        
        // 检查是否有子分类
        long childCount = this.count(new LambdaQueryWrapper<ParamCategory>()
                .eq(ParamCategory::getParentId, id));
        if (childCount > 0) {
            throw new RuntimeException("该分类下存在子分类，无法删除");
        }
        
        // 检查是否有参数使用该分类
        long paramCount = paramDefinitionMapper.selectCount(new LambdaQueryWrapper<ParamDefinition>()
                .eq(ParamDefinition::getCategoryId, id));
        if (paramCount > 0) {
            throw new RuntimeException("该分类下存在参数，无法删除");
        }
        
        return this.removeById(id);
    }

    @Override
    public List<ParamCategoryVO> getChildCategories(Long parentId) {
        LambdaQueryWrapper<ParamCategory> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ParamCategory::getParentId, parentId)
                   .eq(ParamCategory::getStatus, 1)
                   .orderByAsc(ParamCategory::getSortOrder);
        
        List<ParamCategory> categories = this.list(queryWrapper);
        return categories.stream()
                .map(entity -> convertToVO(entity, false))
                .collect(Collectors.toList());
    }

    @Override
    public boolean adjustCategorySortOrder(Long categoryId, Integer targetSortOrder) {
        ParamCategory category = this.getById(categoryId);
        if (category == null) {
            return false;
        }
        
        category.setSortOrder(targetSortOrder);
        category.setUpdateTime(new Date());
        
        return this.updateById(category);
    }

    @Override
    public boolean toggleCategoryStatus(Long id, Integer status) {
        ParamCategory category = this.getById(id);
        if (category == null) {
            throw new RuntimeException("分类不存在");
        }
        
        // 如果要禁用分类，检查是否有子分类或参数
        if (status == 0) {
            long childCount = this.count(new LambdaQueryWrapper<ParamCategory>()
                    .eq(ParamCategory::getParentId, id)
                    .eq(ParamCategory::getStatus, 1));
            if (childCount > 0) {
                throw new RuntimeException("该分类下存在启用的子分类，无法禁用");
            }
        }
        
        category.setStatus(status);
        category.setUpdateTime(new Date());
        
        return this.updateById(category);
    }

    @Override
    public boolean isCategoryCodeAvailable(String categoryCode, Long excludeId) {
        LambdaQueryWrapper<ParamCategory> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ParamCategory::getCategoryCode, categoryCode);
        if (excludeId != null) {
            queryWrapper.ne(ParamCategory::getId, excludeId);
        }
        return this.count(queryWrapper) == 0;
    }

    @Override
    public ParamCategoryVO getCategoryStatistics(Long categoryId) {
        ParamCategoryVO categoryVO = getCategoryDetail(categoryId);
        if (categoryVO == null) {
            return null;
        }
        
        // 统计子分类数量
        long childCount = this.count(new LambdaQueryWrapper<ParamCategory>()
                .eq(ParamCategory::getParentId, categoryId));
        categoryVO.setChildCount((int) childCount);
        
        // 统计参数数量
        long paramCount = paramDefinitionMapper.selectCount(new LambdaQueryWrapper<ParamDefinition>()
                .eq(ParamDefinition::getCategoryId, categoryId));
        categoryVO.setParamCount((int) paramCount);
        
        return categoryVO;
    }

    @Override
    public String getCategoryPath(Long categoryId) {
        if (categoryId == null) {
            return "";
        }
        
        List<String> pathParts = new ArrayList<>();
        Long currentId = categoryId;
        
        // 最多查询10层，防止死循环
        int maxDepth = 10;
        int depth = 0;
        
        while (currentId != null && depth < maxDepth) {
            ParamCategory category = this.getById(currentId);
            if (category == null) {
                break;
            }
            
            pathParts.add(0, category.getCategoryName()); // 插入到开头
            currentId = category.getParentId();
            depth++;
        }
        
        return "/" + String.join("/", pathParts);
    }

    // ===== 私有辅助方法 =====

    /**
     * 获取所有启用的分类
     */
    private List<ParamCategory> getAllEnabledCategories() {
        LambdaQueryWrapper<ParamCategory> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ParamCategory::getStatus, 1)
                   .orderByAsc(ParamCategory::getSortOrder)
                   .orderByAsc(ParamCategory::getCreateTime);
        return this.list(queryWrapper);
    }

    /**
     * 构建分类树形结构
     */
    private List<ParamCategoryTreeVO> buildCategoryTree(List<ParamCategory> allCategories, Long parentId) {
        return allCategories.stream()
                .filter(category -> Objects.equals(category.getParentId(), parentId))
                .map(category -> {
                    ParamCategoryTreeVO treeVO = convertToTreeVO(category);
                    
                    // 递归构建子节点
                    List<ParamCategoryTreeVO> children = buildCategoryTree(allCategories, category.getId());
                    treeVO.setChildren(children);
                    treeVO.setChildCount(children.size());
                    treeVO.setIsLeaf(children.isEmpty());
                    
                    // 计算层级
                    treeVO.setLevel(calculateLevel(category.getId()));
                    
                    // 设置标签（包含统计信息）
                    int paramCount = getParamCountByCategory(category.getId());
                    treeVO.setParamCount(paramCount);
                    treeVO.setLabel(category.getCategoryName() + " (" + paramCount + ")");
                    
                    return treeVO;
                })
                .sorted(Comparator.comparing(ParamCategoryTreeVO::getSortOrder))
                .collect(Collectors.toList());
    }

    /**
     * 转换为TreeVO
     */
    private ParamCategoryTreeVO convertToTreeVO(ParamCategory entity) {
        ParamCategoryTreeVO treeVO = new ParamCategoryTreeVO();
        treeVO.setId(entity.getId());
        treeVO.setCode(entity.getCategoryCode());
        treeVO.setName(entity.getCategoryName());
        treeVO.setParentId(entity.getParentId());
        treeVO.setSortOrder(entity.getSortOrder());
        treeVO.setStatus(entity.getStatus());
        treeVO.setSelectable(entity.getStatus() == 1);
        treeVO.setExpanded(false);
        
        // 根据分类类型设置不同图标
        if (entity.getParentId() == null) {
            treeVO.setIcon("folder"); // 顶级分类
        } else {
            treeVO.setIcon("folder-open"); // 子分类
        }
        
        return treeVO;
    }

    /**
     * 转换为VO
     */
    private ParamCategoryVO convertToVO(ParamCategory entity, boolean includeStatistics) {
        ParamCategoryVO vo = new ParamCategoryVO();
        BeanUtils.copyProperties(entity, vo);
        
        // 设置状态描述
        vo.setStatusDesc(entity.getStatus() == 1 ? "启用" : "禁用");
        
        // 设置父分类名称
        if (entity.getParentId() != null) {
            ParamCategory parentCategory = this.getById(entity.getParentId());
            if (parentCategory != null) {
                vo.setParentName(parentCategory.getCategoryName());
            }
        }
        
        // 设置分类路径
        vo.setCategoryPath(getCategoryPath(entity.getId()));
        
        // 计算层级
        vo.setLevel(calculateLevel(entity.getId()));
        
        // 包含统计信息
        if (includeStatistics) {
            // 统计子分类数量
            long childCount = this.count(new LambdaQueryWrapper<ParamCategory>()
                    .eq(ParamCategory::getParentId, entity.getId()));
            vo.setChildCount((int) childCount);
            
            // 统计参数数量
            vo.setParamCount(getParamCountByCategory(entity.getId()));
        }
        
        return vo;
    }

    /**
     * 计算分类层级
     */
    private Integer calculateLevel(Long categoryId) {
        int level = 1;
        Long currentParentId = this.getById(categoryId).getParentId();
        
        while (currentParentId != null && level < 10) { // 最多10层
            level++;
            ParamCategory parent = this.getById(currentParentId);
            if (parent == null) break;
            currentParentId = parent.getParentId();
        }
        
        return level;
    }

    /**
     * 获取分类下的参数数量
     */
    private Integer getParamCountByCategory(Long categoryId) {
        long count = paramDefinitionMapper.selectCount(new LambdaQueryWrapper<ParamDefinition>()
                .eq(ParamDefinition::getCategoryId, categoryId));
        return (int) count;
    }

    /**
     * 检查是否为后代分类
     */
    private boolean isDescendant(Long ancestorId, Long descendantId) {
        Long currentParentId = this.getById(descendantId).getParentId();
        int depth = 0;
        
        while (currentParentId != null && depth < 10) { // 防止死循环
            if (currentParentId.equals(ancestorId)) {
                return true;
            }
            ParamCategory parent = this.getById(currentParentId);
            if (parent == null) break;
            currentParentId = parent.getParentId();
            depth++;
        }
        
        return false;
    }
}




